﻿@using StackExchange.Opserver.Data.Elastic
@using StackExchange.Opserver.Views.Elastic
@model DashboardModel
@{
    Layout = null;
    var c = Model.Current.Cluster;
    var n = Model.Current.Node;
    var os = n.Stats.OS;
    var jvm = n.Stats.JVM;
    var fs = n.Stats.FileSystem;
    var transport = n.Stats.Transport;
}
<div class="bottom-sub-section">
    <div class="summary-dashboard">
        <h3 class="header"><a href="/elastic">Elastic</a><span class="note">:</span> @c.Name<span class="note">: </span> @n.Name</h3>
        <div class="left-col">
            <div class="section-wrap refresh-group" data-name="instance-summary">
                <table>
                    @Helpers.SectionHeader("Summary")
                    <tbody>
                        <tr>
                            <td>Cluster</td>
                            <td title="Unique ID: @c.Nodes.UniqueId">@c.Name</td>
                        </tr>
                        <tr>
                            <td>Node</td>
                            <td title="Host: @n.Hostname
Transport: @n.Stats.TransportAddress">@n.Name</td>
                        </tr>
                        <tr>
                            <td>ID</td>
                            <td>@n.GUID</td>
                        </tr>
                        <tr>
                            <td>Version</td>
                            <td><a target="_blank" href="http://www.elasticsearch.org/downloads/">@(n != null ? n.Version.ToString() : "Unknown")</a></td>
                        </tr>
                        <tr>
                            <td>Role</td>
                            <td>@(c.Status.Data.MasterNode == n.GUID ? "Master" : "Slave") <span class="note">(<a href="#/elastic/summary/settings">View Settings</a>)</span></td>
                        </tr>
                    </tbody>
                </table> 
            </div>
            @if (os != null)
            {
                <div class="section-wrap refresh-group" data-name="instance-os">
                    <table>
                        @Helpers.SectionHeader("System")
                        <tbody>
                            @if (os.UptimeInMilliseconds > 0)
                            {
                                var upTime = TimeSpan.FromMilliseconds(os.UptimeInMilliseconds);
                                <tr>
                                    <td>Uptime</td>
                                    <td title="@upTime.ToReadableString()">@upTime.ToTimeStringMini(4)</td>
                                </tr>
                            }
                            @if (os.CPU != null)
                            {
                            <tr>
                                <td>CPU</td>
                                <td title="System: @os.CPU.System%
User: @os.CPU.User%
@if (os.LoadAverage != null) {<text>Load average: @(string.Join(",", os.LoadAverage))</text>}">@(100 - os.CPU.Idle)% 
                                    @if (os.LoadAverage != null){<text>(@string.Join(", ", os.LoadAverage))</text>}</td>
                            </tr>
                            }
                            @if (os.Memory != null)
                            {
                                var totalMemory = os.Memory.ActualFreeInbytes + os.Memory.ActualUsedInBytes;
                                var percentMemoryUsed = 100 * os.Memory.ActualUsedInBytes / (decimal)totalMemory;
                                <tr>
                                    <td>Memory</td>
                                    <td>
                                        @(decimal.Round(percentMemoryUsed, 2) + "%") (@os.Memory.ActualUsedInBytes.ToSize() / @totalMemory.ToSize())
                                        <div class="memory-bar">
                                            <div class="space-used">
                                                <div class="used good" style="width: @percentMemoryUsed%"></div>
                                            </div>
                                        </div>
                                    </td>
                                </tr>
                            }
                            @if (os.Swap != null)
                            {
                            <tr>
                                <td>Swap</td>
                                <td>
                                    @os.Swap.UsedInBytes.ToSize() / @((os.Swap.UsedInBytes + os.Swap.FreeInBytes).ToSize()) <span>(@os.Swap.FreeInBytes.ToSize() free)</span>
                                </td>
                            </tr>
                            }
                            @if (os.CPU == null && os.Memory == null && os.Swap == null)
                            {
                                <tr>
                                    <td colspan="2" class="no-content">No System Stats Available</td>
                                </tr>
                            }
                        </tbody>
                    </table>
                </div>
            
            }
            @if (jvm != null)
            {
                var uptime = TimeSpan.FromMilliseconds(jvm.UptimeInMilliseconds);
                var gcTime = TimeSpan.FromMilliseconds(jvm.GC.CollectionTimeInMilliseconds);
                <div class="section-wrap refresh-group" data-name="instance-jvm">
                    <table>
                        @Helpers.SectionHeader("Java Virtual Machine")
                        <tbody>
                            <tr>
                                <td>Uptime</td>
                                <td title="@uptime.ToReadableString()">@uptime.ToTimeStringMini(4)</td>
                            </tr>
                            <tr>
                                <td>Memory (Heap)</td>
                                <td>@jvm.Memory.HeapUsedInBytes.ToSize() <span class="note">(@jvm.Memory.HeapCommittedInBytes.ToSize() committed)</span></td>
                            </tr>
                            <tr>
                                <td>Memory (Non-Heap)</td>
                                <td>@jvm.Memory.NonHeapUsedInBytes.ToSize() <span class="note">(@jvm.Memory.NonHeapCommittedInBytes.ToSize() committed)</span></td>
                            </tr>
                            <tr title="
@foreach (var k in jvm.Memory.Pools.Keys)
{
    // TODO: Fix once used_in_bytes in NEST is corrected
    var val = jvm.Memory.Pools[k];
    <text>
@k:
  Used: @val.Used (@val.PeakUsed peak)
  Max: @val.Max (@val.PeakMax peak)</text>
}">
                                <td>Memory Pools</td>
                                <td>@jvm.Memory.Pools.Keys.Count.ToComma()</td>
                            </tr>
                            <tr>
                                <td>Threads</td>
                                <td>@jvm.Threads.Count.ToComma() <span class="note">(@jvm.Threads.PeakCount.ToComma() peak)</span></td>
                            </tr>
                            <tr>
                                <td>Garbage Collection Runs</td>
                                <td>@jvm.GC.CollectionCount.ToComma() <span class="note" title="@gcTime.ToReadableString()">(@gcTime.ToTimeStringMini(4))</span></td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            }
            @if (fs != null && fs.Data != null)
            {
                <div class="section-wrap refresh-group" data-name="instance-filesystem">
                    <div class="summary-section-header">File System</div>
                    @foreach (var fsd in fs.Data)
                    {
                        var percentUsed = 100*(fsd.TotalInBytes - fsd.AvailableInBytes)/(float) fsd.TotalInBytes;
                        <div class="section-wrap@(fs.Data.Length == 1 ? "" : " half-wrap") volume" title="Mount: @fsd.Mount
Path: @fsd.Path
Queue: @fsd.DiskQueue

Total: @fsd.TotalInBytes.ToSize()
Free: @fsd.FreeInBytes.ToSize()
Available: @fsd.AvailableInBytes.ToSize()
                    
Reads: @fsd.DiskReads.ToComma() (@fsd.DiskReadSizeInBytes.ToSize())
Writes: @fsd.DiskWrites.ToComma() (@fsd.DiskWriteSizeInBytes.ToSize())">
                            <div class="volume-label"><span class="note">Mount:</span> @fsd.Mount</div>
                            <div class="volume-usage">@((fsd.TotalInBytes - fsd.AvailableInBytes).ToSize()) / @fsd.TotalInBytes.ToSize() <span class="note">(@fsd.AvailableInBytes.ToSize() free)</span></div>
                            <div class="volume-bar">
                                <div class="space-used" style="width: auto;"><div class="used good" style="width:@percentUsed%"></div></div>
                            </div>
                        </div>
                    }
                </div>
            }
            @if (transport != null)
            {
                <div class="section-wrap refresh-group" data-name="instance-transport">
                    <table>
                        @Helpers.SectionHeader("Transport")
                        <tbody>
                            <tr>
                                <td>Open Connections</td>
                                <td>@transport.ServerOpen.ToComma()</td>
                            </tr>
                            <tr>
                                <td>Received</td>
                                <td>@transport.RXSizeInBytes.ToSize()</td>
                            </tr>
                            <tr>
                                <td>Sent</td>
                                <td>@transport.TXSizeInBytes.ToSize()</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            }
        </div>
        <div class="right-col">
            @{
                var indexStats = c.Stats.Data != null ? c.Stats.Data.GetIndexStats() : null;
            }
            @if (indexStats == null)
            {
                <div class="section-wrap refresh-group" data-name="instance-indexes-global">
                    <div class="summary-section-header">Cluster Indexes</div>
                    <div class="no-content">No Indexes Found</div>
                    @if (n != null && n.Version < ElasticCluster.MinIndexInfoVersion)
                    {
                        <div class="warning" style="text-align: center">Note: elasticsearch <a href="https://github.com/elasticsearch/elasticsearch/issues/2862" target="_blank">changed the index API</a> in version 0.90+<br />Index info is not fetched in prior versions</div>
                    }
                </div>
            }
            else
            {
                var gs = c.Stats.Data.GlobalStats;
                var indexes = c.HealthStatus.Data.Indices;
                <div class="section-wrap refresh-group" data-name="instance-indexes-global">
                    <div class="summary-section-header">Cluster Index Stats</div>
                    <table>
                        <thead>
                            <tr>
                                <th></th>
                                <th>Primary</th>
                                <th>Total</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td>Searches</td>
                                <td title="Query time: @TimeSpan.FromMilliseconds(gs.Primaries.Search.QueryTimeInMilliseconds).ToReadableString()">@gs.Primaries.Search.QueryTotal.ToComma()</td>
                                <td title="Query time: @TimeSpan.FromMilliseconds(gs.Total.Search.QueryTimeInMilliseconds).ToReadableString()" class="note">@gs.Total.Search.QueryTotal.ToComma()</td>
                            </tr>
                            <tr>
                                <td>Documents</td>
                                <td>@gs.Primaries.Documents.Count.ToComma()</td>
                                <td class="note">@gs.Total.Documents.Count.ToComma()</td>
                            </tr>
                            <tr>
                                <td>Documents (Deleted)</td>
                                <td>@gs.Primaries.Documents.Deleted.ToComma()</td>
                                <td class="note">@gs.Total.Documents.Deleted.ToComma()</td>
                            </tr>
                            <tr>
                                <td>Size</td>
                                <td>@gs.Primaries.Store.SizeInBytes.ToSize()</td>
                                <td class="note">@gs.Total.Store.SizeInBytes.ToSize()</td>
                            </tr>
                            <tr>
                                <td>Indexed</td>
                                <td title="Time taken: @TimeSpan.FromMilliseconds(gs.Primaries.Indexing.TimeInMilliseconds).ToReadableString()">@gs.Primaries.Indexing.Total.ToComma()</td>
                                <td title="Time taken: @TimeSpan.FromMilliseconds(gs.Total.Indexing.TimeInMilliseconds).ToReadableString()" class="note">@gs.Total.Indexing.Total.ToComma()</td>
                            </tr>
                            <tr>
                                <td>Gets</td>
                                <td>@gs.Primaries.Get.Total.ToComma()</td>
                                <td class="note">@gs.Total.Get.Total.ToComma()</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
                <div class="section-wrap refresh-group" data-name="instance-indexes">
                    <div class="summary-section-header">Cluster Indexes
                        <a href="#/elastic/summary/indices" class="top-right-nav">View Detail</a></div>
                    <table>
                        <thead>
                            <tr>
                                <th>Index</th>
                                <th>Searches</th>
                                <th>Docs <span class="note">(Size) xCount</span></th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach (var i in indexes.OrderByWorst().ThenBy(i => { int j; return int.TryParse(i.Name, out j) ? j : 0; }).ThenBy(i => i.Name))
                            {
                                var indexStat = indexStats[i.Name];
                                <tr title="Status: @i.StringStatus
Shards: @i.NumberOfShards.ToComma()
Replicas: @i.NumberOfReplicas.ToComma()

Active: @i.ActiveShards.ToComma()
Active (Primary): @i.ActivePrimaryShards.ToComma()
Initializing: @i.InitializingShards.ToComma()
Relocating: @i.RelocatingShards.ToComma()
Unassigned: @i.UnassignedShards.ToComma()">
                                    <td>@i.IconSpan() 
                                        <a href="#/elastic/index/@i.Name/shards">@c.GetIndexAliasedName(i.Name)</a></td>
                                    <td>@indexStat.Total.Search.QueryTotal.ToComma()</td>
                                    <td>@indexStat.Primaries.Documents.Count.ToComma() <span class="note">(@indexStat.Primaries.Store.SizeInBytes.ToSize()) <span title="@i.NumberOfReplicas.Pluralize("replica")">x@(i.NumberOfReplicas+1)</span></span></td>
                                </tr>
                            }
                        </tbody>
                    </table>
                </div>
            }
        </div>
    </div>
</div>
@switch (Model.Popup)
{
    case DashboardModel.Popups.Indices:
        @Html.Partial("Indices", Model.Current)
        break;
}